home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / tex / miscnix.zip / TAIL.C < prev    next >
Text File  |  1988-05-28  |  5KB  |  208 lines

  1. #include <stdio.h>
  2. #define    ERROR    0
  3. #define    MAXINT    32767
  4. #define    CPMEOF    26    /* Control Z */
  5.  
  6. /**    TAIL    Print last several lines of a file.
  7.  
  8.     Usage:    tail [-|+n[lbc][r]] [file ...]
  9.         where n is the number of lines (l), 512 byte blocks (b), or
  10.         characters (c) from the beginning (+) or end (-) of the file.
  11.         The 'r' option causes the lines to be printed in reverse order.
  12.         Default is -10 (or -32767 if 'r' is set).
  13.  
  14.         One or more files may be given; also, standard input will be
  15.         included in the list if it is a pipe or file.  If more than one
  16.         file is given, the files will be separated by lines of the form:
  17.             ==> file.nam <==
  18.  
  19.     Note:    If you want to recompile this, make sure your C library allows
  20.         you to do fseek() on stdin.
  21.  
  22.     No copyright, dammit:  this is PUBLIC DOMAIN!!!
  23. */
  24.  
  25. char    plus;
  26. long    numarg;
  27. char    unit    ='l';
  28. char    revmode;
  29.  
  30. #define    BUFLEN    512
  31. char    buf[BUFLEN];
  32. #define    BUFLEN2    512
  33. char    buf2[BUFLEN2];
  34. char    *bufpos,*bufend;
  35.  
  36. long    ftell();
  37. long    bgnpos;
  38. long    filepos;
  39.  
  40. usage() {
  41.     puts("Usage:  tail [-|+#[lbc][r]] [file ...]");
  42.     puts("where # is the number of lines from the back (or front) of the file");
  43.     puts("and the file is standard input by default.");
  44.     exit(1);
  45. }
  46.  
  47. readback(f)
  48.     FILE *f; {
  49.     int    len;
  50.  
  51.     len=BUFLEN;
  52.     if (bgnpos>filepos-len) len=filepos-bgnpos;
  53.     filepos-=len;
  54.     fseek(f,filepos,0);
  55.     fread(buf,1,len,f);
  56.     bufpos=bufend= &buf[len];
  57. }
  58.  
  59. processfile(f,s,b)
  60.     FILE *f;
  61.     char *s;    /* file name */
  62.     int b; {    /* >0 if we want to print it */
  63.     long    lastpos;
  64.     int    nlines;
  65.     int    len;
  66.  
  67.     if (b>0) {fputs("==> ",stdout); fputs(s,stdout); puts(" <==");}
  68.     bgnpos=0;
  69.  
  70.     if (plus) {    /* if plus, make use of that information */
  71.         bgnpos=numarg;
  72.         if (unit!='c') {
  73.         bufpos=bufend= &buf;
  74.         nlines=numarg;
  75.         while (nlines>0) {
  76.             bufpos=strnchr(bufpos,bufend-bufpos,'\n');
  77.             if (bufpos<bufend) {
  78.             --nlines;
  79.             ++bufpos;
  80.             } else {
  81.             bufpos= &buf;
  82.             bufend= &buf[fread(buf,1,BUFLEN,f)];
  83.             if (bufend<=bufpos) break;
  84.             }
  85.         }
  86.         bgnpos=ftell(f) - (int) (bufend-bufpos);
  87.         } /* end if unit */
  88.     }
  89.     else if (unit=='c') {
  90.         fseek(f,0L,2);
  91.         bgnpos=ftell(f)-numarg;
  92.         if (bgnpos<0) bgnpos=0;
  93.     }
  94.  
  95.     nlines=0;
  96.     if (!plus && unit!='c') nlines=numarg;
  97.     else if (revmode) nlines=MAXINT;
  98.  
  99.     /* go reversely through the file */
  100.  
  101.     if (nlines) {
  102.         fseek(f,0L,2);
  103.         filepos=ftell(f);
  104.         readback(f);
  105.         if (bufpos > &buf && *(bufpos-1)==CPMEOF) --bufpos;
  106.         if (bufpos > &buf && *(bufpos-1)=='\n') --bufpos;
  107.         do {
  108.         lastpos=filepos + (int) (bufpos-&buf);
  109.         for (;;) {
  110.             bufpos=strrnchr(&buf,bufpos-&buf,'\n');
  111.             if (bufpos>=&buf) break;
  112.             readback(f);
  113.             if (bufpos<=&buf) {nlines=0; bufpos= &buf-1; break;}
  114.         }
  115.         if (revmode) {
  116.             len = (int) (lastpos-filepos) - (bufend-&buf);
  117.             if (len <= 0) {
  118.             if (*(bufend+len-1)=='\r') --len;
  119.             fwrite(bufpos+1,1,len+bufend-bufpos-1,stdout);
  120.             } else {
  121.             fwrite(bufpos+1,1,bufend-bufpos-1,stdout);
  122.             fseek(f,filepos + (int) (bufend-&buf),0);
  123.             while (len>BUFLEN2) {
  124.                 fread(buf2,1,BUFLEN2,f);
  125.                 fwrite(buf2,1,BUFLEN2,stdout);
  126.                 len-=BUFLEN2;
  127.             }
  128.             fread(buf2,1,len,f);
  129.             if (buf2[len-1]=='\r') --len;
  130.             fwrite(buf2,1,len,stdout);
  131.             }
  132.             putchar('\n');
  133.         }
  134.         } while (--nlines > 0);
  135.         bgnpos=filepos + (int) (bufpos-&buf+1);
  136.     } /* end if */
  137.  
  138.     if (revmode) return;
  139.  
  140.     /* print the requested number of lines */
  141.  
  142.     fseek(f,bgnpos,0);
  143.     for (;;) {
  144.         /*fgets(buf,BUFLEN-1,f); len=strlen(buf);*/
  145.         len=fgetss(buf,BUFLEN-1,f);
  146.         if (len<0) break;
  147.         if (len<BUFLEN-2) {    /* if end of line found */
  148.         buf[len++]='\r';
  149.         buf[len++]='\n';
  150.         }
  151.         fwrite(buf,1,len,stdout);    /* faster than puts */
  152.     }
  153. }
  154.  
  155. main(argc,argv)
  156.     int argc;
  157.     char **argv; {
  158.     int    arg0    =1;
  159.     int    arg;
  160.     FILE    *f;
  161.     char    c, *s;
  162.  
  163.     /* parse numeric argument */
  164.  
  165.     if (argc>1 && (argv[1][0]=='-' || (argv[1][0]=='+' && ++plus))) {
  166.         s=argv[1]+1;
  167.         c=*s;
  168.         if (isdigit(c)) {
  169.         while (isdigit(c)) {
  170.             numarg=numarg*10+(c-'0');
  171.             c= *++s;
  172.         }
  173.         unit=c;
  174.         if (c=='b') {numarg<<=9; unit='c';}
  175.         else if (c!='c' && c!='l') --s;
  176.         ++s;
  177.         }
  178.         if (*s == 'r') {++s; ++revmode;}
  179.         if (*s) usage(); 
  180.         ++arg0;
  181.     }
  182.     if (numarg==0) {plus=0; numarg=(revmode? MAXINT: 10);}
  183.  
  184.     arg=arg0;
  185.     --argc;
  186.  
  187.     if (!isatty(0)) {
  188.         --arg0;
  189.         processfile(stdin,"Standard input",argc-arg0);
  190.     }
  191.  
  192.     if (arg0>argc) usage();
  193.  
  194.     for (; arg <= argc; ++arg) {
  195.         if (arg>arg0) putchar('\n');
  196.         /* Open file for input */
  197.         s=argv[arg];
  198.         f=fopen(s,"r");
  199.         if (f==ERROR) {
  200.         fputs("Cannot open ",stderr);
  201.         fputs(s,stderr);
  202.         fputs("\n",stderr);
  203.         exit(1);
  204.         }
  205.         processfile(f,s,argc-arg0);
  206.     }
  207. }
  208.